/*
 * Copyright Hundsun Technologies Inc. All Rights Reserved.
 */

package protos

import (
	"encoding/hex"
	"fmt"
	"regexp"

	"github.com/golang/protobuf/proto"
	"hundsun.com/hsl/hschain/common/crypto"
)

var addressFmt = regexp.MustCompile("^[0-9A-Fa-f]{40}$")

var (
	errInvalidAddressFmt = "account '%s' does not match  pattern '^[0-9A-Fa-f]{40}$'"
)

// Hash 数据的哈希。
// 可能需要支持不同的哈希算法，所以此处未指定长度
type Hash []byte

// Equals 判断哈希是否相等
func (h Hash) Equals(other Hash) bool {
	if len(h) != len(other) {
		return false
	}
	if len(h) > 0 {
		for i := len(h) - 1; i >= 0; i-- {
			if h[i] != other[i] {
				return false
			}
		}
	}

	return true
}

// GetShortString 获取缩短后的哈希对应的字符串（一般用于打印日志）
func (h Hash) GetShortString() string {
	if len(h) <= 4 {
		return hex.EncodeToString(h)
	}
	return hex.EncodeToString(h[0:4])
}

// Address 地址
type Address string

// Validate 校验地址
func (addr Address) Validate() error {
	if !addressFmt.MatchString(string(addr)) {
		return fmt.Errorf(errInvalidAddressFmt, addr)
	}
	return nil
}

// GetShortString 获取缩短后的地址（一般用于打印日志）
func (addr Address) GetShortString() string {
	if len(addr) <= 8 {
		return string(addr)
	}
	return string(addr)[0:8]
}

// ParseAddressFromPublicKeyBytes 字节数组格式的公钥转成地址
func ParseAddressFromPublicKeyBytes(pubKeyBytes []byte) (Address, error) {
	pubKeyHash, err := crypto.Hash(pubKeyBytes)
	if err != nil {
		return "", err
	}
	address := hex.EncodeToString(pubKeyHash[12:])
	return Address(address), nil
}

// GenesisCoinbase 创世纪块中的coinbase
const GenesisCoinbase = Address("0x0000000000000000000000000000000000000000")

// MainChainID 主链ID
const MainChainID = "main"

// EnhancedProtoMessage 增强的protobuf消息
type EnhancedProtoMessage interface {
	proto.Message
	// GetXXXNamespace 获取命名空间
	GetXXXNamespace() string

	// GetXXXKey 获取存储逐渐
	GetXXXKey() string

	// GetXXXSearchFields 获取可用于查询的字段及其值
	GetXXXSearchFields() map[string]interface{}
}

// SignableMessage 可签名的消息
type SignableMessage interface {
	//Sign 对消息进行签名
	Sign(keyPair crypto.KeyPair)

	//Verify 验证消息中的签名
	Verify() bool
}
